package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.constants.CoreConstant;
import cn.com.dcsgo.domain.dto.SysDeptSaveDTO;
import cn.com.dcsgo.domain.dto.SysDeptUpdateDTO;
import cn.com.dcsgo.domain.po.SysDept;
import cn.com.dcsgo.domain.po.SysUser;
import cn.com.dcsgo.domain.vo.SysDeptVO;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.mapper.SysDeptMapper;
import cn.com.dcsgo.mapper.SysUserMapper;
import cn.com.dcsgo.service.SysDeptService;
import cn.com.dcsgo.utils.ConverterUtils;
import cn.hutool.core.lang.Assert;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * SysDeptServiceImpl
 *
 * @author Dcsgo
 * @since 2/6/2025 下午 8:03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl implements SysDeptService {
    private final SysDeptMapper sysDeptMapper;
    private final SysUserMapper sysUserMapper;

    @Override
    public List<SysDeptVO> getLevelList() {
        List<SysDept> deptList = sysDeptMapper.selectAll();
        if (CollectionUtils.isEmpty(deptList)) {
            return new ArrayList<>(0);
        }
        return this.buildLevelStructure(deptList);
    }

    @Override
    public SysDept getOne(Long deptId) {
        return sysDeptMapper.selectByPrimaryKey(deptId);
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int save(SysDeptSaveDTO saveDTO) {
        SysDept saveData = new SysDept();
        BeanUtils.copyProperties(saveDTO, saveData);

        // 查表设置部门领导信息
        setDeptLeaderInfo(saveData);

        saveData.setCreateBy(getUsername());
        saveData.setCreateTime(new Date());

        return sysDeptMapper.insertSelective(saveData);
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int update(SysDeptUpdateDTO updateDTO) {
        SysDept updateData = sysDeptMapper.selectByPrimaryKey(updateDTO.getDeptId());
        Assert.notNull(updateData, "修改的部门不存在");

        ConverterUtils.syncFieldsWithNullOnEqual(updateDTO, updateData, "deptId");

        // 上级部门不能为当前部门
        Assert.isTrue(
                !updateData.getDeptId().equals(updateData.getParentId()),
                "上级部门不能为本部门"
        );

        //修改了部门领导 更新部门领导信息
        if (updateData.getLeaderId() != null) {
            setDeptLeaderInfo(updateData);
        } else {
            // 未修改部门领导 不更新部门领导信息
            updateData.setLeaderName(null);
            updateData.setPhone(null);
            updateData.setEmail(null);
        }

        updateData.setCreateBy(null);
        updateData.setCreateTime(null);
        updateData.setUpdateBy(getUsername());
        updateData.setUpdateTime(new Date());

        return sysDeptMapper.updateByPrimaryKeySelective(updateData);
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int remove(Long deptId) {
        if (sysDeptMapper.hasChild(deptId)) {
            throw new BusinessException("当前部门有下级部门，不允许删除");
        }
        return sysDeptMapper.deleteByPrimaryKey(deptId);
    }

    /**
     * 设置部门领导信息
     * 领导编号为 null 或 0 表示不设置部门领导信息
     *
     * @param sysDept 部门
     */
    private void setDeptLeaderInfo(SysDept sysDept) {
        if (sysDept.getLeaderId() != null && sysDept.getLeaderId() != 0) {
            SysUser leader = sysUserMapper.selectByPrimaryKey(sysDept.getLeaderId());
            if (leader == null) {
                if (sysDept.getDeptId() == null) {
                    log.error("数据不一致!添加部门时指定的部门领导:{}不存在", sysDept.getLeaderId());
                } else {
                    log.error("数据不一致!修改部门:{}时指定的部门领导:{}不存在", sysDept.getDeptId(), sysDept.getLeaderId());
                }
                throw new BusinessException("操作失败，请联系管理员");
            }
            sysDept.setLeaderName(leader.getNickName());
            sysDept.setPhone(leader.getPhone());
            sysDept.setEmail(leader.getEmail());
        }
    }

    /**
     * 构建具有层级关系的部门的信息集合
     *
     * @param deptList 部门的信息集合
     * @return 具有层级关系的部门的信息集合
     */
    private List<SysDeptVO> buildLevelStructure(List<SysDept> deptList) {
        // 将所有部门VO根据id存放到一个map中遍历deptList设置其对于下级部门
        Map<Long, SysDeptVO> deptVoMap = deptList.stream().collect(
                Collectors.toMap(
                        SysDept::getDeptId,
                        sysDept -> {
                            SysDeptVO sysDeptVO = new SysDeptVO();
                            BeanUtils.copyProperties(sysDept, sysDeptVO);
                            return sysDeptVO;
                        }));
        List<SysDeptVO> result = new LinkedList<>();

        deptList.forEach(dept -> {
            // 根部门 最高级别的部门 直接添加到结果集
            if (dept.getParentId().equals(CoreConstant.DEFAULT_PARENT_ID)) {
                result.add(deptVoMap.get(dept.getDeptId()));
            } else {
                // 子部门 将它添加到其上级部门的子部门集合中(非根部门总是链接在根部门下面的)
                SysDeptVO parent = deptVoMap.get(dept.getParentId());
                if (parent == null) {
                    log.error("数据库中数据有误!请查看部门表中部门id为:{}的部门的上级部门(其部门id为:{})是否存在", dept.getDeptId(), dept.getParentId());
                    throw new BusinessException("操作失败，请联系管理员");
                }
                parent.getChildren().add(deptVoMap.get(dept.getDeptId()));
            }
        });
        return result;
    }
}
